﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Web;
using Earthwatchers.Data;
using Earthwatchers.Models;
using Earthwatchers.Services.Security;
using Microsoft.ApplicationServer.Http.Dispatcher;

namespace Earthwatchers.Services.Resources
{
    [ServiceContract]
    public class EarthwatcherResource
    {
        private readonly IEarthwatcherRepository earthwatcherRepository;
        private readonly ILandRepository landRepository;

        public EarthwatcherResource(IEarthwatcherRepository earthwatcherRepository,ILandRepository landRepository)
        {
            this.earthwatcherRepository = earthwatcherRepository;
            this.landRepository = landRepository;
        }

        [WebGet(UriTemplate = "{id}")]
        public HttpResponseMessage<Earthwatcher> Get(int id, HttpRequestMessage request)
        {
            var earthwatcher = earthwatcherRepository.GetEarthwatcher(id);
            if (earthwatcher == null)
            {
                return new HttpResponseMessage<Earthwatcher>(HttpStatusCode.NotFound);
            }
            EarthwatcherLinks.AddLinks(earthwatcher, request);
            return new HttpResponseMessage<Earthwatcher>(earthwatcher) { StatusCode = HttpStatusCode.OK };
        }

        [WebGet(UriTemplate = "/name={name}")]
        public HttpResponseMessage<Earthwatcher> GetByName(string name, HttpRequestMessage request)
        {
            var earthwatcher = earthwatcherRepository.GetEarthwatcher(name);
            if (earthwatcher == null)
            {
                var response = new HttpResponseMessage<Earthwatcher>(HttpStatusCode.NotFound);
                return response;
            }
            EarthwatcherLinks.AddLinks(earthwatcher, request);
            return new HttpResponseMessage<Earthwatcher>(earthwatcher) { StatusCode = HttpStatusCode.OK };
        }

        [WebGet(UriTemplate = "")]
        public HttpResponseMessage<List<Earthwatcher>> GetAll(HttpRequestMessage request)
        {
            var earthwatchers = earthwatcherRepository.GetAllEarthwatchers();
            foreach (var earthwatcher in earthwatchers)
            {
                EarthwatcherLinks.AddLinks(earthwatcher, request);
            }
            return new HttpResponseMessage<List<Earthwatcher>>(earthwatchers) { StatusCode = HttpStatusCode.OK };
        }

        [BasicHttpAuthorization(Role.Admin)]
        [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
        public HttpResponseMessage Delete(int id, HttpRequestMessage<Earthwatcher> request)
        {
            var earthwatcherDb = earthwatcherRepository.GetEarthwatcher(id);

            if (earthwatcherDb != null)
            {
                if (earthwatcherDb.LandId.HasValue)
                {
                    landRepository.UnassignLand((int)earthwatcherDb.LandId);
                }
                earthwatcherRepository.DeleteEarthwatcher(earthwatcherDb.Id);

                return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
            }
            return new HttpResponseMessage { StatusCode = HttpStatusCode.NotFound };
        }

        [BasicHttpAuthorization(Role.Admin)]
        [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
        public HttpResponseMessage UpdateEarthwatcher(int id, Earthwatcher earthwatcher)
        {
            var earthwatcherDb = earthwatcherRepository.GetEarthwatcher(id);
            if (earthwatcherDb != null)
            {
                earthwatcherRepository.UpdateEarthwatcher(earthwatcher.Id, earthwatcher);
                return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
            }
            return new HttpResponseMessage { StatusCode = HttpStatusCode.NotFound };
        }
        
        [BasicHttpAuthorization(Role.Admin)]
        [WebInvoke(UriTemplate = "", Method = "POST")]
        public HttpResponseMessage<Earthwatcher> Post(Earthwatcher earthwatcher, HttpRequestMessage<Earthwatcher> request)
        {
            var earthwatcherDb = earthwatcherRepository.GetEarthwatcher(earthwatcher.Name);
            if (earthwatcherDb == null)
            {
                earthwatcher.Guid = Guid.NewGuid();
                earthwatcherRepository.CreateEarthwatcher(earthwatcher);

                // assign land
                if (String.IsNullOrEmpty(earthwatcher.Basecamp)) earthwatcher.Basecamp = "borneo";
                
                var geohex = earthwatcherRepository.AssignLandToEarthwatcher(earthwatcher.Guid.ToString(),earthwatcher.Basecamp);

                if (geohex != null)
                {
                    UpdateLandStatusNotChecked(earthwatcher.Guid);
                    var response = new HttpResponseMessage<Earthwatcher>(earthwatcher) { StatusCode = HttpStatusCode.Created };
                    var uriBuilder = new UriBuilder(request.RequestUri) { Path = earthwatcher.Uri };
                    response.Headers.Location = uriBuilder.Uri;
                    return response;
                }

                // possible cause: there is no land to be assigned
                // delete the user again...
                earthwatcherRepository.DeleteEarthwatcher(earthwatcher.Id);
                // create entry in elmah
                string error = String.Format("error: there is no free land available. basecamp: {0}, name: {1}",earthwatcher.Basecamp, earthwatcher.Name);
                Elmah.ErrorSignal.FromCurrentContext().Raise(new ApplicationException(error));
                throw new HttpResponseException(error);


                //return new HttpResponseMessage<Earthwatcher>(null) { StatusCode = HttpStatusCode.InternalServerError, ReasonPhrase = "There is no land to be assigned. Contact the administrator" };
            }
            throw new HttpResponseException("error: user already exists");

            //return new HttpResponseMessage<Earthwatcher>(earthwatcher) { StatusCode = HttpStatusCode.NotFound, };
        }

        [BasicHttpAuthorization(Role.Admin)]
        [WebInvoke(UriTemplate = "{id}/reassignland", Method = "POST")]
        public HttpResponseMessage<Earthwatcher> ReassignLand(int id, HttpRequestMessage<Earthwatcher> request)
        {
            var earthwatcherDb = earthwatcherRepository.GetEarthwatcher(id);
            if (earthwatcherDb != null)
            {
                // we do not need to reassign land for now
                if (earthwatcherDb.LandId != null)
                {
                    // set status to unwatched
                    var land = landRepository.GetLand((int)earthwatcherDb.LandId);
                    landRepository.UnassignLand(land.Id);
                    landRepository.UpdateLandStatus(land.Id, LandStatus.Unwatched);

                    // assign new land
                    var geohex = earthwatcherRepository.AssignLandToEarthwatcher(earthwatcherDb.Guid.ToString(), "borneo");
                    if (geohex != null)
                    {
                        earthwatcherDb = earthwatcherRepository.GetEarthwatcher(id);
                        UpdateLandStatusNotChecked(earthwatcherDb.Guid);

                        return new HttpResponseMessage<Earthwatcher>(earthwatcherDb) { StatusCode = HttpStatusCode.Created };
                    }
                    else
                    {
                        // possible cause: there is no land to be assigned
                        return new HttpResponseMessage<Earthwatcher>(null) { StatusCode = HttpStatusCode.InternalServerError, ReasonPhrase= "There is no land to be assigned. Contact the administrator" };
                    }

                }
            }
            return new HttpResponseMessage<Earthwatcher>(null) { StatusCode = HttpStatusCode.NotFound };
        }


        private void UpdateLandStatusNotChecked(Guid guid)
        {
            var earthwatcher = earthwatcherRepository.GetEarthwatcher(guid);
            var landId = earthwatcher.LandId;
            if (landId.HasValue)
            {
                var land = landRepository.GetLand((int)landId);
                landRepository.UpdateLandStatus(land.Id, LandStatus.NotChecked);
            }
        }
    }
}





